import akshare as ak
import pandas as pd
import numpy as np
import time
import logging

# 定义一些可配置的指标参数
short_ma_period = 8
long_ma_period = 25
rsi_period = 16
oversold_threshold = 28
macd_fast_period = 10
macd_slow_period = 24
macd_signal_period = 8
bollinger_n_period = 20
bollinger_k = 2
kdj_window = 9
# 定义涨停阈值（这里假设涨幅超过9.5%为涨停，可根据实际情况调整）
limit_up_threshold = 0.095
# 用于统计历史涨停次数的天数
history_days = 60


def get_stock_daily_data(symbol, start_date, end_date):
    logger = logging.getLogger(__name__)
    start_time = time.time()
    try:
        print(f"[{time.ctime()}] 正在获取 {symbol} 的股票数据...")
        stock_data = ak.stock_zh_a_daily(symbol=symbol, start_date=start_date, end_date=end_date)
        elapsed_time = time.time() - start_time
        if elapsed_time > 5:
            logger.warning(f"获取 {symbol} 数据超时，跳过。")
            return pd.DataFrame()
        print(f"[{time.ctime()}] 成功获取 {symbol} 的股票数据。")
        return stock_data
    except Exception as e:
        logger.error(f"获取 {symbol} 股票数据时出错: {e}")
        return pd.DataFrame()


def calculate_moving_averages(data, short_period, long_period):
    data['sma_short'] = data['close'].rolling(window=short_period).mean()
    data['sma_long'] = data['close'].rolling(window=long_period).mean()
    return data


def detect_rsi_oversold(data, rsi_period, oversold_threshold):
    close_diff = data['close'].diff()
    up_gains = close_diff.where(close_diff > 0, 0)
    down_losses = -close_diff.where(close_diff < 0, 0)
    avg_gain = up_gains.rolling(rsi_period).mean()
    avg_loss = down_losses.rolling(rsi_period).mean()
    rs = avg_gain / avg_loss
    rsi = 100 - (100 / (1 + rs))
    data['rsi'] = rsi
    return rsi.iloc[-1] < oversold_threshold, rsi.iloc[-1]


def detect_macd_crossover(data, fast_period, slow_period, signal_period):
    ema_fast = data['close'].ewm(span=fast_period).mean()
    ema_slow = data['close'].ewm(span=slow_period).mean()
    macd_line = ema_fast - ema_slow
    signal_line = macd_line.ewm(span=signal_period).mean()
    data['macd'] = macd_line
    data['signal'] = signal_line
    data['hist'] = macd_line - signal_line
    return macd_line.iloc[-1] > signal_line.iloc[-1] and macd_line.iloc[-2] <= signal_line.iloc[-2], macd_line.iloc[-1], signal_line.iloc[-1]


def analyze_volume_change(data):
    volume_change = data['volume'].pct_change()
    if volume_change.empty:
        return "成交量数据不可用"
    last_volume_change = volume_change.iloc[-1]
    if last_volume_change > 0.3:
        return "成交量显著增加"
    elif last_volume_change < -0.3:
        return "成交量显著减少"
    else:
        return "成交量相对稳定"


def calculate_price_volatility(data):
    returns = data['close'].pct_change()
    volatility = returns.std()
    return volatility


def calculate_bollinger_bands(data, n_period, k):
    rolling_mean = data['close'].rolling(n_period).mean()
    rolling_std = data['close'].rolling(n_period).std()
    data['bollinger_upper'] = rolling_mean + (k * rolling_std)
    data['bollinger_middle'] = rolling_mean
    data['bollinger_lower'] = rolling_mean - (k * rolling_std)
    return data


def calculate_kdj(data, window):
    low_prices = data['low'].rolling(window=window).min()
    high_prices = data['high'].rolling(window=window).max()
    close_prices = data['close']
    rsv = ((close_prices - low_prices) / (high_prices - low_prices)) * 100
    k = pd.Series(rsv).ewm(com=2).mean()
    d = k.ewm(com=2).mean()
    j = 3 * k - 2 * d
    data['k'] = k
    data['d'] = d
    data['j'] = j
    return data


def detect_kdj_crossover(data, window):
    return data['k'].iloc[-1] > data['d'].iloc[-1] and data['k'].iloc[-2] <= data['d'].iloc[-2], data['k'].iloc[-1], data['d'].iloc[-1]


def get_strategy_reasons(data, short_period, long_period, rsi_period, oversold_threshold, fast_period, slow_period, signal_period, n_period, k, window):
    reasons = []
    # 移动平均线交叉原因
    if data['sma_short'].iloc[-1] > data['sma_long'].iloc[-1] and data['sma_short'].iloc[-2] <= data['sma_long'].iloc[-2]:
        reasons.append("短期均线向上穿过长期均线")
    else:
        reasons.append("短期均线未向上穿过长期均线")
    # RSI 超卖原因
    is_rsi_oversold, rsi_value = detect_rsi_oversold(data, rsi_period, oversold_threshold)
    if is_rsi_oversold:
        reasons.append(f"RSI 超卖，值为{rsi_value}")
    else:
        reasons.append(f"RSI 未超卖，值为{rsi_value}")
    # MACD 金叉原因
    is_macd_crossover, macd_value, signal_value = detect_macd_crossover(data, fast_period, slow_period, signal_period)
    if is_macd_crossover:
        reasons.append(f"MACD 金叉，MACD 值为{macd_value}，信号值为{signal_value}")
    else:
        reasons.append(f"MACD 未金叉，MACD 值为{macd_value}，信号值为{signal_value}")
    # 成交量变化原因
    volume_change_result = analyze_volume_change(data)
    reasons.append(volume_change_result)
    # 价格波动率原因
    price_volatility = calculate_price_volatility(data)
    if price_volatility < 0.12:
        reasons.append("价格波动相对较低")
    else:
        reasons.append("价格波动相对较高")
    # 布林带策略原因
    if data['close'].iloc[-1] > data['bollinger_upper'].iloc[-1]:
        reasons.append("股价突破布林带上轨")
    elif data['close'].iloc[-1] < data['bollinger_lower'].iloc[-1]:
        reasons.append("股价跌破布林带下轨")
    else:
        reasons.append("股价在布林带内")
    # KDJ 策略原因
    kdj_result, k_value, d_value = detect_kdj_crossover(data, window)
    if kdj_result:
        reasons.append(f"KDJ 金叉，K 值为{k_value}，D 值为{d_value}")
    else:
        reasons.append(f"KDJ 未金叉，K 值为{k_value}，D 值为{d_value}")
    return reasons


def has_limit_up_gene(data, limit_up_threshold, history_days):
    # 统计历史涨停次数
    limit_up_count = sum(data['close'].pct_change() >= limit_up_threshold)
    # 判断当日涨幅是否较大（这里假设涨幅超过5%具有一定涨停倾向，可调整）
    current_gain = data['close'].pct_change().iloc[-1]
    strong_gain_today = current_gain > 0.05
    # 结合一些技术指标判断，这里假设满足部分条件即认为有涨停基因

    # 新增评估维度
    # 1. 主力资金流入情况
    main_capital_inflow = 0  # 假设可以从数据中获取主力资金流入值，这里只是占位
    significant_capital_inflow = main_capital_inflow > 10000000  # 根据实际情况调整阈值

    # 2. 新闻舆情分析（假设正面新闻较多可能推动股价上涨）
    positive_news_count = 0  # 假设可以通过某种方式获取新闻正面评价数量，这里只是占位
    positive_news_influence = positive_news_count > 5  # 根据实际情况调整阈值

    technical_conditions = (detect_rsi_oversold(data, rsi_period, oversold_threshold)[0] or detect_macd_crossover(data, macd_fast_period, macd_slow_period, macd_signal_period)[0]) and \
                           analyze_volume_change(data) == "成交量显著增加" and \
                           calculate_price_volatility(data) < 0.12 and \
                           detect_kdj_crossover(data, kdj_window)[0]

    return limit_up_count > 0 or (strong_gain_today and technical_conditions and significant_capital_inflow and positive_news_influence)


def predict_buy_point(symbol, start_date, end_date, short_window=short_ma_period, long_window=long_ma_period, rsi_period=rsi_period,
                      oversold_threshold=oversold_threshold, macd_fast_period=macd_fast_period,
                      macd_slow_period=macd_slow_period, macd_signal_period=macd_signal_period,
                      bollinger_n_period=bollinger_n_period, bollinger_k=bollinger_k, kdj_window=kdj_window):
    stock_data = get_stock_daily_data(symbol, start_date, end_date)
    if stock_data.empty:
        return "数据获取失败", None, "无法判断"
    stock_data['symbol'] = [symbol] * len(stock_data)
    stock_data = calculate_moving_averages(stock_data, short_window, long_window)
    stock_data = calculate_bollinger_bands(stock_data, bollinger_n_period, bollinger_k)
    stock_data = calculate_kdj(stock_data, kdj_window)
    reasons = get_strategy_reasons(stock_data, short_window, long_window, rsi_period, oversold_threshold, macd_fast_period, macd_slow_period, macd_signal_period, bollinger_n_period, bollinger_k, kdj_window)
    has_gene = has_limit_up_gene(stock_data, limit_up_threshold, history_days)

    # 尝试对未来趋势进行简单分析（非常不准确，仅供示例）
    future_trend = "不确定"
    if stock_data['sma_short'].iloc[-1] > stock_data['sma_long'].iloc[-1] and stock_data['close'].iloc[-1] < stock_data['bollinger_upper'].iloc[-1] and has_gene:
        future_trend = "可能上涨，潜在买点"
        if current_gain > 0.08 and positive_news_influence and significant_capital_inflow:
            future_trend = "很可能上涨，较好的买点"
    elif stock_data['sma_short'].iloc[-1] < stock_data['sma_long'].iloc[-1] or stock_data['close'].iloc[-1] > stock_data['bollinger_upper'].iloc[-1]:
        future_trend = "可能下跌，谨慎观察"

    # 综合策略判断
    if (stock_data['sma_short'].iloc[-1] > stock_data['sma_long'].iloc[-1] and stock_data['sma_short'].iloc[-2] <=
            stock_data['sma_long'].iloc[-2]) and \
            (detect_rsi_oversold(stock_data, rsi_period, oversold_threshold)[0] or detect_macd_crossover(stock_data, macd_fast_period, macd_slow_period, macd_signal_period)[0]) and \
            analyze_volume_change(stock_data) == "成交量显著增加" and \
            calculate_price_volatility(stock_data) < 0.12 and \
            (stock_data['close'].iloc[-1] < stock_data['bollinger_upper'].iloc[-1] and stock_data['close'].iloc[-1] >
             stock_data['bollinger_middle'].iloc[-1]) and \
            detect_kdj_crossover(stock_data, kdj_window)[0] and has_gene:
        print(f"[{time.ctime()}] {symbol} 是较好的买点且有涨停基因，原因: {', '.join(reasons)}")
        return "较好的买点且有涨停基因", reasons, future_trend
    elif ((stock_data['sma_short'].iloc[-1] > stock_data['sma_long'].iloc[-1] and stock_data['sma_short'].iloc[-2] <=
           stock_data['sma_long'].iloc[-2]) and \
          (detect_rsi_oversold(stock_data, rsi_period, oversold_threshold)[0] or detect_macd_crossover(stock_data, macd_fast_period, macd_slow_period, macd_signal_period)[0]) and \
          analyze_volume_change(stock_data) == "成交量显著增加" and \
          calculate_price_volatility(stock_data) < 0.12) or \
            ((stock_data['close'].iloc[-1] < stock_data['bollinger_upper'].iloc[-1] and stock_data['close'].iloc[-1] >
              stock_data['bollinger_middle'].iloc[-1]) and \
             detect_kdj_crossover(stock_data, kdj_window)[0] and has_gene):
        print(f"[{time.ctime()}] {symbol} 是潜在买点且有涨停基因，原因: {', '.join(reasons)}")
        return "潜在买点且有涨停基因", reasons, future_trend
    elif has_gene:
        print(f"[{time.ctime()}] {symbol} 有涨停基因，但买点不明确，原因: {', '.join(reasons)}")
        return "有涨停基因，但买点不明确", reasons, future_trend
    else:
        print(f"[{time.ctime()}] {symbol} 目前未发现明显买点信号，原因: {', '.join(reasons)}")
        return "目前未发现明显买点信号", reasons, future_trend


def get_all_stock_codes():
    print(f"[{time.ctime()}] 获取所有股票代码...")
    # 获取 A 股股票代码和名称数据
    stock_info = ak.stock_info_a_code_name()

    def add_prefix(code):
        if code.startswith("300"):
            return "sz" + code
        elif code.startswith("60"):
            return "sh" + code
        elif code.startswith("00"):
            return "sz" + code
        else:
            return None
    # 为股票代码添加前缀并筛选
    stock_info["code_with_prefix"] = stock_info["code"].apply(add_prefix)
    filtered_stock_info = stock_info.dropna(subset=['code_with_prefix'])
    print(f"[{time.ctime()}] 完成获取所有股票代码，共 {len(filtered_stock_info)} 个。")
    return filtered_stock_info


def main():
    all_stock_codes = get_all_stock_codes()
    total_stocks = len(all_stock_codes)
    processed_stocks = 0
    better_buy_points = []
    potential_buy_points = []
    unclear_buy_points = []
    no_buy_points = []

    today = pd.Timestamp.now().strftime('%Y-%m-%d')
    start_date = (pd.Timestamp(today) - pd.Timedelta(days=120)).strftime('%Y-%m-%d')

    for code_with_prefix in all_stock_codes['code_with_prefix']:
        processed_stocks += 1
        print(f"[{time.ctime()}] 正在处理第 {processed_stocks} / {total_stocks} 个股票: {code_with_prefix}")
        category, reasons, future_trend = predict_buy_point(code_with_prefix, start_date, today)
        if category == "较好的买点且有涨停基因":
            better_buy_points.append((code_with_prefix, reasons, future_trend))
        elif category == "潜在买点且有涨停基因":
            potential_buy_points.append((code_with_prefix, reasons, future_trend))
        elif category == "有涨停基因，但买点不明确":
            unclear_buy_points.append((code_with_prefix, reasons, future_trend))
        else:
            no_buy_points.append((code_with_prefix, reasons, future_trend))

    print("较好的买点且有涨停基因:")
    for stock_info in better_buy_points:
        print(f"股票代码: {stock_info[0]}")
        print(f"原因: {', '.join(stock_info[1])}")
        print(f"未来趋势: {stock_info[2]}")
        print()

    print("潜在买点且有涨停基因:")
    for stock_info in potential_buy_points:
        print(f"股票代码: {stock_info[0]}")
        print(f"原因: {', '.join(stock_info[1])}")
        print(f"未来趋势: {stock_info[2]}")
        print()

    print("有涨停基因，但买点不明确:")
    for stock_info in unclear_buy_points:
        print(f"股票代码: {stock_info[0]}")
        print(f"原因: {', '.join(stock_info[1])}")
        print(f"未来趋势: {stock_info[2]}")
        print()

    print("未发现明显买点信号:")
    for stock_info in no_buy_points:
        print(f"股票代码: {stock_info[0]}")
        print(f"原因: {', '.join(stock_info[1])}")
        print(f"未来趋势: {stock_info[2]}")


if __name__ == "__main__":
    main()